#pragma once

#include "Assert.h"
#include "CoreApi.h"
using namespace loco;

void test_Vector2()
{
	// constructor
	{
		Vector2 v1(1.0f, -2.0f);
		ASSERT(v1.x == 1.0f);
		ASSERT(v1.y == -2.0f);

		Vector2 v2(3.0f);
		ASSERT(v2.x == 3.0f);
		ASSERT(v2.y == 3.0f);
	}

	// near_equal
	{
	Vector2 v1(4.0f, -3.0f);
	ASSERT(Vector2::near_equal(v1, Vector2(4.0f + 0.5f * DELTA, -3.0f)));
	ASSERT(Vector2::near_equal(v1, Vector2(4.0f + 2.0f * DELTA, -3.0f)) == false);
	ASSERT(Vector2::near_equal(v1, Vector2(4.0f, -3.0f + 2.0f * DELTA)) == false);
}

	// operator+
	{
		Vector2 v1(1.0f, -2.0f);
		Vector2 v2(3.0f, 5.0f);
		ASSERT(Vector2::near_equal((v1 + v2), Vector2(4.0f, 3.0f)));
	}

	// operator-
	{
		Vector2 v1(1.0f, -2.0f);
		Vector2 v2(3.0f, 5.0f);
		ASSERT(Vector2::near_equal((v1 - v2), Vector2(-2.0f, -7.0f)));
	}

	// operator*
	{
		Vector2 v1(2.0f, 3.0f);
		Vector2 v2(0.25f, 0.5f);
		ASSERT(Vector2::near_equal((v1 * v2), Vector2(0.5f, 1.5f)));
	}

	// operator/
	{
		Vector2 v1(2.0f, 3.0f);
		Vector2 v2(4.0f, 2.0f);
		ASSERT(Vector2::near_equal((v1 / v2), Vector2(0.5f, 1.5f)));
	}

	// operator+=
	{
		Vector2 v1(1.0f, -2.0f);
		Vector2 v2(3.0f, 5.0f);
		ASSERT(Vector2::near_equal((v1 += v2), Vector2(4.0f, 3.0f)));
	}

	// operator-=
	{
		Vector2 v1(1.0f, -2.0f);
		Vector2 v2(3.0f, 5.0f);
		ASSERT(Vector2::near_equal((v1 -= v2), Vector2(-2.0f, -7.0f)));
	}

	// operator*=
	{
		Vector2 v1(2.0f, 3.0f);
		Vector2 v2(0.25f, 0.5f);
		ASSERT(Vector2::near_equal((v1 *= v2), Vector2(0.5f, 1.5f)));
	}

	// operator/=
	{
		Vector2 v1(2.0f, 3.0f);
		Vector2 v2(4.0f, 2.0f);
		ASSERT(Vector2::near_equal((v1 /= v2), Vector2(0.5f, 1.5f)));
	}

	// operator/=
	{
		Vector2 v1(2.0f, 3.0f);
		Vector2 v2(4.0f, 2.0f);
		ASSERT(Vector2::near_equal((v1 /= v2), Vector2(0.5f, 1.5f)));
	}

	// operator==
	{
		Vector2 v1(1.0f, 1.0f);
		Vector2 v2(1.0f, 2.0f);
		Vector2 v3(2.0f, 2.0f);
		ASSERT((v1 == v2) == false);
		ASSERT((v2 == v3) == false);
		ASSERT((v2 == v2) == true);
	}

	// operator!=
	{
		Vector2 v1(1.0f, 1.0f);
		Vector2 v2(1.0f, 2.0f);
		Vector2 v3(2.0f, 2.0f);
		ASSERT((v1 != v2) == true);
		ASSERT((v2 != v3) == true);
		ASSERT((v2 != v2) == false);
	}

	// operator>
	{
		Vector2 v1(1.0f, 2.0f);
		Vector2 v2(2.0f, 4.0f);
		Vector2 v3(2.0f, 2.0f);
		ASSERT((v2 > v1) == true);
		ASSERT((v1 > v2) == false);
		ASSERT((v3 > v1) == false);
	}

	// operator<
	{
		Vector2 v1(1.0f, 2.0f);
		Vector2 v2(2.0f, 4.0f);
		Vector2 v3(3.0f, 2.0f);
		ASSERT((v1 < v2) == true);
		ASSERT((v2 < v1) == false);
		ASSERT((v1 < v3) == false);
	}

	// operator>=
	{
		Vector2 v1(1.0f, 2.0f);
		Vector2 v2(2.0f, 4.0f);
		Vector2 v3(2.0f, 2.0f);
		ASSERT((v2 >= v1) == true);
		ASSERT((v1 >= v2) == false);
		ASSERT((v3 >= v1) == true);
	}

	// operator<=
	{
		Vector2 v1(1.0f, 2.0f);
		Vector2 v2(2.0f, 4.0f);
		Vector2 v3(3.0f, 2.0f);
		ASSERT((v1 <= v2) == true);
		ASSERT((v2 <= v1) == false);
		ASSERT((v1 <= v3) == true);
	}

	// norm
	{
		Vector2 v1(4.0f, -3.0f);
		ASSERT(v1.norm() == 5.0f);
	}

	// square_norm
	{
		Vector2 v1(4.0f, -3.0f);
		ASSERT(v1.square_norm() == 25.0f);
	}

	// normalize
	{
		Vector2 v1(4.0f, -3.0f);
		ASSERT(v1.normalize() == Vector2(4.0f / 5.0f, -3.0f / 5.0f));
	}

	// reflection
	{
		Vector2 v1(-1.0f, -1.0f);
		Vector2 n1(1.0f, 0.0f);
		Vector2 n2(0.0f, 1.0f);
		ASSERT(Vector2::near_equal(Vector2::reflection(v1, n1), Vector2(1.0, -1.0f)));
		ASSERT(Vector2::near_equal(Vector2::reflection(v1, n2), Vector2(-1.0, 1.0f)));
	}

	// Distance
	{
		Vector2 v1(1.0f, -1.0f);
		Vector2 v2(5.0f, 2.0f);
		ASSERT(Vector2::distance(v1, v2) == 5.0f);
	}

	// SquareDistance
	{
		Vector2 v1(1.0f, -1.0f);
		Vector2 v2(5.0f, 2.0f);
		ASSERT(Vector2::square_distance(v1, v2) == 25.0f);
	}

	// Dot Product
	{
		Vector2 v1(1.0f, 0.0f);
		Vector2 v2(0.0f, 1.0f);
		ASSERT(Vector2::dot(Vector2(1.0f, 0.0f), Vector2(0.0, 1.0f)) == 0.0f);
		ASSERT(Vector2::dot(Vector2(2.0f, 3.0f), Vector2(-1.0, -4.0f)) == -14.0f);
	}

	// lerp
	{
		ASSERT(Vector2::lerp(Vector2(-1.0f, 2.0f), Vector2(3.0f, 4.0f), 0.25f) == Vector2(0.0f, 2.5f));
		ASSERT(Vector2::lerp(Vector2(-1.0f, 2.0f), Vector2(3.0f, 4.0f), Vector2(0.25f, 0.5f)) == Vector2(0.0f, 3.0f));
	}

	// Check constant value
	{
		ASSERT(Vector2::zero == Vector2(0.0f, 0.0f));
		ASSERT(Vector2::unit_x == Vector2(1.0f, 0.0f));
		ASSERT(Vector2::unit_y == Vector2(0.0f, 1.0f));
		ASSERT(Vector2::one == Vector2(1.0f, 1.0f));
	}
}